package com.jk.vehicle.mini.schedule.components;

import com.alibaba.excel.util.CollectionUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jk.vehicle.core.utils.TimeUtil;
import com.jk.vehicle.mini.entity.MileageStatisticsDay;
import com.jk.vehicle.mini.entity.MileageStatisticsMoon;
import com.jk.vehicle.mini.entity.MileageStatisticsWeek;
import com.jk.vehicle.mini.service.MileageRecordService;
import com.jk.vehicle.mini.service.MileageStatisticsDayService;
import com.jk.vehicle.mini.service.MileageStatisticsMoonService;
import com.jk.vehicle.mini.service.MileageStatisticsWeekService;
import com.jk.vehicle.mini.vo.StatisticsVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Condition;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 车辆行程统计
 */
@Slf4j
@Component
public class MileageStatistics {
    @Resource
    private MileageStatisticsDayService mileageStatisticsDayService;

    @Resource
    private MileageStatisticsWeekService mileageStatisticsWeekService;

    @Resource
    private MileageStatisticsMoonService mileageStatisticsMoonService;

    @Resource
    private MileageRecordService mileageRecordService;

    /**
     * 分页从第一页开始
     */
    private final static int START_PAGE = 1;
    /**
     * 默认的单页面数据量
     */
    private final static int DEFAULT_PAGE_SIZE = 100;

    /**
     * 车辆行程按日统计
     * @param someDate 指定统计某日
     */
    @Async(value = "taskExecutor")
    public void dayMileageStatistics(Date someDate, String dsName) {
        log.info("------------- 执行日里程统计定时器 -------------");
        doDayMileageStatisticsPage(START_PAGE, DEFAULT_PAGE_SIZE, someDate, dsName);
    }

    /**
     * 车辆行程按周统计
     * @param someDate 指定统计某日期当周
     */
    @Async(value = "taskExecutor")
    public void weekMileageStatistics(Date someDate, String dsName) {
        log.info("------------- 执行周里程统计定时器 -------------");
        doWeekMileageStatisticsPage(START_PAGE, DEFAULT_PAGE_SIZE, someDate, dsName);
    }

    /**
     * 车辆行程按月统计
     * @param someDate 指定统计某日期当月
     */
    @Async(value = "taskExecutor")
    public void moonMileageStatistics(Date someDate, String dsName) {
        log.info("------------- 执行月里程统计定时器 -------------");
        doMoonMileageStatistics(START_PAGE, DEFAULT_PAGE_SIZE, someDate, dsName);
    }

    /**
     * 执行车辆行程按月统计
     * @param page 页码
     * @param size 单页数据量
     * @param someDate 指定某日期
     */
    private void doMoonMileageStatistics(int page, int size, Date someDate, String dsName){
        List<Long> bicycleIdList = doPage(page, size, dsName);
        // 如果列表不为空，则进行下一步操作，否则结束
        if (CollectionUtils.isEmpty(bicycleIdList)){
            return;
        }
        if (someDate == null){
            someDate = new Date();
        }
        // 查询本月第一天日期
        Date moonFirstDate = TimeUtil.getFirstDayDateOfMonth(someDate);
        Date moonLastDate = TimeUtil.getLastDayOfMonth(someDate);
        String moonFirstDay = TimeUtil.formatDate(moonFirstDate, "yyyy-MM-dd");
        String moonLastDay = TimeUtil.formatDate(moonLastDate, "yyyy-MM-dd");
        StatisticsVO statisticsVO;    // 总里程
        MileageStatisticsMoon mileageStatisticsMoon;  // 车辆月统计对象
        Condition condition = new Condition(MileageStatisticsMoon.class);
        // 循环进行车辆本月里程的统计
        for (Long id : bicycleIdList){
            // 删除本月数据
            condition.clear();
            condition.createCriteria().andEqualTo("startDate", TimeUtil.formatDate(moonFirstDate, "yyyy-MM-dd"))
                    .andEqualTo("bicycleId", id);
            mileageStatisticsMoonService.deleteByCondition(condition, dsName);

            // 计算月份
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(someDate);
            // 获取当前月
            int month = calendar.get(Calendar.MONTH) + 1;

            // 新增本周新的数据
            statisticsVO = mileageRecordService.queryMileageByDay(moonFirstDay, moonLastDay, id, dsName);
            mileageStatisticsMoon = MileageStatisticsMoon.MileageStatisticsMoonBuilder.aMileageStatisticsMoon()
                    .withBicycleId(id)
                    .withStartDate(moonFirstDate)
                    .withEndDate(moonLastDate)
                    .withMileage(statisticsVO.getTotalMileage())
                    .withRecordMoon(month)
                    .withAvgSpeed(new BigDecimal(0))
                    .withRideTime(statisticsVO.getTotalSeconds())
                    .withTopSpeed(statisticsVO.getTopSpeed())
                    .build();
            if (statisticsVO.getTotalSeconds() != 0L){
                mileageStatisticsMoon.setAvgSpeed(statisticsVO.getTotalMileage().divide(new BigDecimal(statisticsVO.getTotalSeconds()).divide(new BigDecimal(3600), 8, BigDecimal.ROUND_HALF_UP),
                        2, BigDecimal.ROUND_HALF_UP));
            }
            try{
                mileageStatisticsMoonService.save(mileageStatisticsMoon, dsName);
            }catch (Exception e){
                log.error("新增本周里程统计时，出现异常:{}，异常车辆id：{}", e.getMessage(), id);
            }
        }
        // 循环处理下一页数据
        doMoonMileageStatistics(++page, size, someDate, dsName);
    }

    /**
     * 执行车辆行程按周统计
     * @param page 页码
     * @param size 单页数据量
     * @param someDate 指定某日期
     */
    private void doWeekMileageStatisticsPage(int page, int size, Date someDate, String dsName){
        List<Long> bicycleIdList = doPage(page, size, dsName);
        // 如果列表不为空，则进行下一步操作，否则结束
        if (CollectionUtils.isEmpty(bicycleIdList)){
            return;
        }
        if (someDate == null){
            someDate = new Date();
        }
        Date weekFirstDate = TimeUtil.getWeekFirstDay(someDate);
        Date weekLastDate = TimeUtil.getWeekLastDay(someDate);
        // 查询本周周一日期
        String weekFirstDay = TimeUtil.formatDate(weekFirstDate, "yyyy-MM-dd");
        String weekLastDay = TimeUtil.formatDate(weekLastDate, "yyyy-MM-dd");
        StatisticsVO statisticsVO;    // 总里程
        MileageStatisticsWeek mileageStatisticsWeek;  // 车辆周统计对象
        Condition condition = new Condition(MileageStatisticsWeek.class);
        // 循环进行车辆本周里程的统计
        for (Long id : bicycleIdList){
            // 删除本周数据
            condition.clear();
            condition.createCriteria().andEqualTo("startDate", TimeUtil.formatDate(weekFirstDate, "yyyy-MM-dd"))
                    .andEqualTo("bicycleId", id);
            mileageStatisticsWeekService.deleteByCondition(condition, dsName);

            // 新增本周新的数据
            statisticsVO = mileageRecordService.queryMileageByDay(weekFirstDay, weekLastDay, id, dsName);
            mileageStatisticsWeek = MileageStatisticsWeek.MileageStatisticsWeekBuilder.aMileageStatisticsWeek()
                    .withBicycleId(id)
                    .withStartDate(weekFirstDate)
                    .withEndDate(weekLastDate)
                    .withMileage(statisticsVO.getTotalMileage())
                    .withRecordWeek(TimeUtil.getWeekOfYear(someDate))
                    .withAvgSpeed(new BigDecimal(0))
                    .withRideTime(statisticsVO.getTotalSeconds())
                    .withTopSpeed(statisticsVO.getTopSpeed())
                    .build();
            if (statisticsVO.getTotalSeconds() != 0L){
                mileageStatisticsWeek.setAvgSpeed(statisticsVO.getTotalMileage().divide(new BigDecimal(statisticsVO.getTotalSeconds()).divide(new BigDecimal(3600), 8, BigDecimal.ROUND_HALF_UP),
                        2, BigDecimal.ROUND_HALF_UP));
            }
            try{
                mileageStatisticsWeekService.save(mileageStatisticsWeek, dsName);
            }catch (Exception e){
                log.error("新增本周里程统计时，出现异常:{}，异常车辆id：{}", e.getMessage(), id);
            }
        }
        // 循环处理下一页数据
        doWeekMileageStatisticsPage(++page, size, someDate, dsName);
    }


    /**
     * 执行日里程统计具体操作
     * @param page 页码
     * @param size 单页数据量
     * @param someDate 指定某日
     */
    private void doDayMileageStatisticsPage(int page, int size, Date someDate, String dsName){
        String someDay = DateFormatUtils.format(someDate, "yyyy-MM-dd");
        if (someDate == null){
            someDay = DateFormatUtils.format(DateUtils.addDays(new Date(), -1), "yyyy-MM-dd");
        }
        // 执行数据分页操作
        List<Long> bicycleIdList = doPage(page, size, dsName);
        // 如果列表不为空，则进行下一步操作，否则结束
        if (CollectionUtils.isEmpty(bicycleIdList)){
            return;
        }
        StatisticsVO statisticsVO;
        MileageStatisticsDay mileageStatisticsDay;
        Condition condition = new Condition(MileageStatisticsDay.class);
        for (Long id : bicycleIdList){
            // 删除本日数据
            condition.clear();
            condition.createCriteria().andEqualTo("recordDay", someDay)
                    .andEqualTo("bicycleId", id);
            mileageStatisticsDayService.deleteByCondition(condition, dsName);

            // 查询昨日总的里程统计并入库
            statisticsVO = mileageRecordService.queryMileageByDay(someDay, someDay, id, dsName);
            // 新建里程统计表数据
            mileageStatisticsDay = MileageStatisticsDay.MileageStatisticsDayBuilder.aMileageStatisticsDay()
                    .withBicycleId(id)
                    .withMileage(statisticsVO.getTotalMileage())
                    .withTopSpeed(statisticsVO.getTopSpeed())
                    .withRideTime(statisticsVO.getTotalSeconds())
                    .withRecordDay(someDate)
                    .withAvgSpeed(new BigDecimal(0))
                    .build();
            if (statisticsVO.getTotalSeconds() != 0L){
                mileageStatisticsDay.setAvgSpeed(statisticsVO.getTotalMileage().divide(new BigDecimal(statisticsVO.getTotalSeconds()).divide(new BigDecimal(3600), 8, BigDecimal.ROUND_HALF_UP),
                        2, BigDecimal.ROUND_HALF_UP));
            }
            try{
                mileageStatisticsDayService.save(mileageStatisticsDay, dsName);
            }catch (Exception e){
                log.error("新增昨日里程统计时，出现异常:{}，异常车辆id：{}", e.getMessage(), id);
            }
        }
        // 循环处理下一页数据
        doDayMileageStatisticsPage(++page, size, someDate, dsName);
    }

    /**
     * 进行分页
     * @param page 页码
     * @param size 单个页面数据量
     * @return 结果
     */
    private List<Long> doPage(int page, int size, String dsName){
        // 进行分页
        PageHelper.startPage(page, size);
        List<Long> tempBicycleIdList = mileageRecordService.queryAllBicycleIds(dsName);
        PageInfo<Long> pageInfo = new PageInfo<>(tempBicycleIdList);
        return pageInfo.getList();
    }
}
